#include "TaskQueue.h"
#include <limits>
#include <algorithm>

void TaskQueue::Push(Task* task)
{
	if (task)
	{
		int priority = task->GetPriority();
		std::unique_lock<std::mutex> lk(mutex_);
		if (list_.size() > 0 && list_.back()->GetPriority() < priority)
		{
			for (auto iter = list_.begin(); iter != list_.end(); iter++)
			{
				if (priority >= (*iter)->GetPriority())
				{
					list_.insert(iter, std::move(task));
					break;
				}
			}
		}
		else
		{
			list_.push_back(std::move(task));
		}
		lk.unlock();
	}
	else
	{
		std::unique_lock<std::mutex> lk(mutex_);
		list_.push_back(std::move(task));
		lk.unlock();
	}
	condition_.notify_one();
}

void TaskQueue::PushFront(Task* task)
{
	task->SetPriority(std::numeric_limits<int>::max());
	std::unique_lock<std::mutex> lk(mutex_);
	list_.push_front(std::move(task));
	lk.unlock();
	condition_.notify_one();
}

Task* TaskQueue::Pop()
{
	std::unique_lock<std::mutex> lk(mutex_);
	condition_.wait(lk, [this] {return !list_.empty(); });
	Task* task = std::move(list_.front());
	list_.pop_front();
	lk.unlock();
	return task;
}

Task* TaskQueue::TryPop()
{
	if (mutex_.try_lock())
	{
		if (!list_.empty())
		{
			Task* task = std::move(list_.front());
			list_.pop_front();
			mutex_.unlock();
			return task;
		}
		mutex_.unlock();
	}
	return nullptr;
}

bool TaskQueue::EraseById(unsigned int id)
{
	std::lock_guard<std::mutex> lk(mutex_);
	if (!list_.empty())
	{
		for (auto iter = list_.begin(); iter != list_.end(); iter++)
		{
			if ((*iter) && (*iter)->GetId() == id)
			{
				list_.erase(iter);
				return true;
			}
		}
	}

	return false;
}

void TaskQueue::EraseByOwner(void* owner)
{
	std::lock_guard<std::mutex> lk(mutex_);
	if (!list_.empty())
	{
		list_.erase(std::remove_if(list_.begin(), list_.end(), [owner](const Task* task) {
			return task && task->GetOwner() == owner;
		}), list_.end());
	}
}


